package com.mezz.bones.framework.outbox.executor.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.exceptions.ExceptionUtil;
import com.mezz.bones.framework.outbox.domain.dto.HttpExecuteParams;
import com.mezz.bones.framework.outbox.domain.entity.OutboxMessage;
import com.mezz.bones.framework.outbox.executor.MessageExecutor;
import com.mezz.bones.framework.outbox.model.ExecuteResult;
import lombok.AllArgsConstructor;
import okhttp3.*;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSON;
import java.util.Map;

@Component
@AllArgsConstructor
public class HttpMessageExecutor implements MessageExecutor {
    private static final MediaType JSON_MEDIA_TYPE = MediaType.parse("application/json; charset=utf-8");
    private final OkHttpClient okHttpClient;

    @Override
    public String tag() {
        return TAG_HTTP;
    }


    /**
     * 执行HTTP请求并返回执行结果。
     * <p>
     * 注意：发件箱模式（Outbox Pattern）在此实现中仅通过HTTP响应状态码判断请求是否成功。
     * 实际应用中，许多接口使用自定义的状态码来判断业务逻辑是否成功。
     * 为了更好地处理这种情况，建议使用 {@link BeanMessageExecutor} 处理更灵活的接口返回数据。
     * </p>
     *
     * @param message 包含HTTP请求参数的OutboxMessage对象
     * @return ExecuteResult对象，包含请求的成功状态、状态码和响应体
     */
    @Override
    public ExecuteResult execute(OutboxMessage message) {
        HttpExecuteParams params = JSON.toJavaObject(message.getExecuteParams(), HttpExecuteParams.class);

        Request.Builder requestBuilder = new Request.Builder()
                .url(buildUrl(message.getExecuteTarget(), params.getQueryParams()))
                .method(params.getMethod(), buildRequestBody(params));

        // 添加请求头
        if (CollUtil.isNotEmpty(params.getHeaders())) {
            params.getHeaders().forEach(requestBuilder::addHeader);
        }

        okhttp3.Response response = null;
        try {

            response = okHttpClient.newCall(requestBuilder.build()).execute();
            if(response.isSuccessful()){
                assert response.body() != null;
                return ExecuteResult.ok(response.body().string());
            }

            return ExecuteResult.error("HTTP请求失败: " + response.message());

        } catch (Exception e) {
            return ExecuteResult.error("HTTP请求失败: " + e.getMessage(), ExceptionUtil.stacktraceToString(e));
        }

    }



    private String buildUrl(String baseUrl, Map<String, String> queryParams) {
        if (queryParams == null || queryParams.isEmpty()) {
            return baseUrl;
        }
        HttpUrl.Builder urlBuilder = HttpUrl.parse(baseUrl).newBuilder();
        queryParams.forEach(urlBuilder::addQueryParameter);
        return urlBuilder.build().toString();
    }

    private RequestBody buildRequestBody(HttpExecuteParams params) {
        switch (params.getRequestType()) {
            case JSON:
                return RequestBody.create(params.getBody(), JSON_MEDIA_TYPE);
            case QUERY_PARAMS:
                // Query parameters are already added to the URL, so no body is needed
                return null;
            case FORM_PARAMS:
                FormBody.Builder formBodyBuilder = new FormBody.Builder();
                if (params.getFormParams() != null) {
                    params.getFormParams().forEach(formBodyBuilder::add);
                }
                return formBodyBuilder.build();
            default:
                throw new IllegalArgumentException("Unsupported request type: " + params.getRequestType());
        }
    }
}